package com.xinsoft.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinsoft.common.Response;
import com.xinsoft.common.exception.BDException;
import com.xinsoft.constant.Const;
import com.xinsoft.entity.dto.*;
import com.xinsoft.entity.po.*;
import com.xinsoft.entity.vo.ScmPurchasePlanItemVo;
import com.xinsoft.entity.vo.ScmPurchasePlanPageVo;
import com.xinsoft.entity.vo.ScmPurchasePlanVo;
import com.xinsoft.service.*;
import com.xinsoft.mapper.ScmPurchasePlanMapper;
import com.xinsoft.utils.TokenUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* @author 13370
* @description 针对表【scm_purchase_plan(采购计划)】的数据库操作Service实现
* @createDate 2023-07-04 14:35:53
*/
@Service
public class ScmPurchasePlanServiceImpl extends ServiceImpl<ScmPurchasePlanMapper, ScmPurchasePlan>
    implements ScmPurchasePlanService{

    @Autowired
    private ScmPurchasePlanItemService scmPurchasePlanItemService;

    @Autowired
    private SysApproveFlowService sysApproveFlowService;

    @Autowired
    private SysApproveFlowNodeService sysApproveFlowNodeService;
    @Autowired
    private SysUserRoleService sysUserRoleService;
    @Autowired
    private SysUserService userService;
    @Autowired
    private SysApproveNodeRelService sysApproveNodeRelService;
    @Autowired
    private ScmUserApproveRefService scmUserApproveRefService;

    @Autowired
    private ScmApproveHisService scmApproveHisService;
    @Autowired
    private ScmPurchaseService scmPurchaseServices;
    @Autowired
    private SysDocumentNumService sysDocumentNumService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response<?> addOrUpdate(ScmPurchasePlanDto purchasePlanDto) {
        ScmPurchasePlan scmPurchasePlan = new ScmPurchasePlan();
        BeanUtils.copyProperties(purchasePlanDto,scmPurchasePlan);
        scmPurchasePlan.setApproveStatus(Const.ApproveStatus.STAGING);
        List<ScmPurchasePlanItem> itemList = purchasePlanDto.getItemList();
        //1、新增/修改采购申请
        if (ObjectUtil.isEmpty(purchasePlanDto.getId())){
            // 更新计划单号
            sysDocumentNumService.incrementLastSerialByDocumentId(Const.DOCUMENT_ID.PURCHASE_PLAN_DOCUMENT);
            this.save(scmPurchasePlan);
        }else {
            this.updateById(scmPurchasePlan);
            LambdaQueryWrapper<ScmPurchasePlanItem> itemLambdaQueryWrapper = new LambdaQueryWrapper<>();
            itemLambdaQueryWrapper.eq(ScmPurchasePlanItem::getPurchasePlanId,purchasePlanDto.getId());
            scmPurchasePlanItemService.remove(itemLambdaQueryWrapper);
        }
        itemList.forEach(item ->{
            item.setPurchasePlanId(scmPurchasePlan.getId());
        });
        scmPurchasePlanItemService.saveBatch(itemList);
        return Response.succeed();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response<?> submintApprove(ScmPurchasePlanDto purchasePlanDto) {
        ScmPurchasePlan scmPurchasePlan = new ScmPurchasePlan();
        BeanUtils.copyProperties(purchasePlanDto,scmPurchasePlan);
        List<ScmPurchasePlanItem> itemList = purchasePlanDto.getItemList();
        scmPurchasePlan.setApproveStatus(Const.ApproveStatus.SUBMIT);
        //1、新增/修改采购申请
        if (ObjectUtil.isEmpty(purchasePlanDto.getId())){
            // 更新计划单号
            sysDocumentNumService.incrementLastSerialByDocumentId(Const.DOCUMENT_ID.SALE_DOCUMENT);
            this.save(scmPurchasePlan);
        }else {
            this.updateById(scmPurchasePlan);
            LambdaQueryWrapper<ScmPurchasePlanItem> itemLambdaQueryWrapper = new LambdaQueryWrapper<>();
            itemLambdaQueryWrapper.eq(ScmPurchasePlanItem::getPurchasePlanId,purchasePlanDto.getId());
            scmPurchasePlanItemService.remove(itemLambdaQueryWrapper);
        }
        itemList.forEach(item ->{
            item.setPurchasePlanId(scmPurchasePlan.getId());
        });
        scmPurchasePlanItemService.saveBatch(itemList);
        //2、提交审批
        approveNodeAdd(scmPurchasePlan.getPurchasePlanCode(), scmPurchasePlan.getId(), Const.ApproveType.CGJH, 1, Const.ApproveTypeName.CGJH);
        return Response.succeed();
    }


    /**
     * 审批采购申请单
     * @param id 采购申请单id
     * @param result 审批结果：0-驳回  1-同意  2-转派
     * @param type 审批源单类型
     * @param transferId 审批结果为转派时：被转派人id
     * @param desc 审批意见
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response<?> approved(Integer id, Integer type, Integer result, Integer transferId, String desc) {

        // 节点结束： 更新、新增 审批历史记录表-用户关联审批表，
        LambdaQueryWrapper<ScmApproveHis> approveHisWrapper = new LambdaQueryWrapper<>();
        approveHisWrapper.eq(ScmApproveHis::getSourceType, type);
        approveHisWrapper.eq(ScmApproveHis::getSourceId, id);
        approveHisWrapper.orderBy(true,false, ScmApproveHis::getNum);
        approveHisWrapper.last("limit 1");
        ScmApproveHis approveHisDO = scmApproveHisService.getOne(approveHisWrapper);
        long between = DateUtil.between(approveHisDO.getCreateTime(), new Date(), DateUnit.HOUR);
        if (ObjectUtil.isNotEmpty(approveHisDO.getExecutionTimeLimit()) && new Long(approveHisDO.getExecutionTimeLimit()).compareTo(between) < 0){
            return Response.fail("超出审批时限：" + approveHisDO.getExecutionTimeLimit() + "小时!");
        }
        LambdaQueryWrapper<ScmUserApproveRef> approveRefWrapper = new LambdaQueryWrapper<>();
        approveRefWrapper.eq(ScmUserApproveRef::getApproveId,approveHisDO.getId());
        approveRefWrapper.eq(ScmUserApproveRef::getApprovePersonId,TokenUtil.getUserId());
        approveRefWrapper.eq(ScmUserApproveRef::getDoComplete,0);
        List<ScmUserApproveRef> scmRefList = scmUserApproveRefService.list(approveRefWrapper);
        Map<Integer, ScmUserApproveRef> scmRefListMap = scmRefList.stream().collect(Collectors.toMap(item -> item.getApprovePersonId(), item -> item, (v1, v2) -> v1));
        ScmUserApproveRef scmUserApproveRef = scmRefListMap.get(TokenUtil.getUserId());
        if (ObjectUtil.isEmpty(scmRefList) || ObjectUtil.isEmpty(scmUserApproveRef)){
            return Response.fail("审批失败，不是审批人不能审批！！");
        }
        //1、驳回 --> 反写源单状态
        if (Const.ApproveResult.bohui.equals(result)){
            scmUserApproveRef.setApproveResult(result);
            scmUserApproveRef.setApproveTime(new Date());
            scmUserApproveRef.setDoComplete(1);
            approveHisDO.setApproveResult(result);
            approveHisDO.setApproveDesc(desc);
            approveHisDO.setDoComplete(1);

            scmRefList.forEach(item->item.setDoComplete(1));
            //采购计划
            if (type.equals(Const.ApproveType.CGJH)){
                ScmPurchasePlan scmPurchasePlan = new ScmPurchasePlan();
                scmPurchasePlan.setId(id);
                scmPurchasePlan.setApproveStatus(Const.ApproveStatus.STAGING);
                this.updateById(scmPurchasePlan);
            }
            //采购订单
            if (type.equals(Const.ApproveType.CGDD)){
                ScmPurchase scmPurchase = new ScmPurchase();
                scmPurchase.setId(id);
                scmPurchase.setApproveStatus(Const.ApproveStatus.STAGING);
                scmPurchaseServices.updateById(scmPurchase);
            }
            //...
        }
        //2、转派
        if (Const.ApproveResult.zhuanpai.equals(result)){
            if (ObjectUtil.isEmpty(transferId)){
                return Response.fail("未选择转派人！");
            }
            scmUserApproveRef.setApproveResult(result);
            scmUserApproveRef.setApproveTime(new Date());
            scmUserApproveRef.setDoComplete(1);
            approveHisDO.setApproveDesc(desc);
            approveHisDO.setDoComplete(1);
            SysUser transferUserDO = userService.getById(transferId);
            ScmUserApproveRef scmTransferApproveRef = new ScmUserApproveRef();
            scmTransferApproveRef.setApproveId(approveHisDO.getId());
            scmTransferApproveRef.setApprovePersonId(transferId);
            scmTransferApproveRef.setApprovePersonName(transferUserDO.getRealName());
            scmTransferApproveRef.setApproveResult(Const.ApproveResult.weichuli);
            scmTransferApproveRef.setDoComplete(0);
            scmUserApproveRefService.save(scmTransferApproveRef);
            scmRefList.forEach(item->item.setDoComplete(1));
        }
        //3、同意
        if (Const.ApproveResult.tongyi.equals(result)){
            scmUserApproveRef.setApproveResult(result);
            scmUserApproveRef.setApproveTime(new Date());
            //当前节点是否结束
            boolean determine = (approveHisDO.getIsCountersign().equals(1) && scmRefList.size() == 1) || approveHisDO.getIsCountersign().equals(0);
            //当前节点未结束
            if (!determine){
                scmUserApproveRef.setDoComplete(0);
            }
            if (determine) {
                scmUserApproveRef.setDoComplete(1);
                approveHisDO.setApproveResult(result);
                approveHisDO.setApproveDesc(desc);
                approveHisDO.setDoComplete(1);
                scmRefList.forEach(item->item.setDoComplete(1));
            }
            //当前节点结束、有下一节点 --> 审批未结束 --> 新增节点历史记录
            if (determine && approveHisDO.getDoNextNode().equals(1)) {
                approveNodeAdd(approveHisDO.getSourceCode(), approveHisDO.getSourceId(), approveHisDO.getSourceType(), approveHisDO.getNum()+1, Const.ApproveTypeName.CGJH);
            }
            //当前节点结束、无下一节点 --> 审批结束 --> 反写源单状态
            if (determine && !approveHisDO.getDoNextNode().equals(1)) {
                //采购计划
                if (type.equals(Const.ApproveType.CGJH)){
                    ScmPurchasePlan scmPurchasePlan = new ScmPurchasePlan();
                    scmPurchasePlan.setId(id);
                    scmPurchasePlan.setApproveStatus(Const.ApproveStatus.APPROVED);
                    this.updateById(scmPurchasePlan);
                }
                //采购订单
                if (type.equals(Const.ApproveType.CGDD)){
                    ScmPurchase scmPurchase = new ScmPurchase();
                    scmPurchase.setId(id);
                    scmPurchase.setApproveStatus(Const.ApproveStatus.APPROVED);
                    scmPurchaseServices.updateById(scmPurchase);
//                    List<ScmPurchasePrice> purchasePrices =
//                    scmPurchasePriceService.saveBatch(purchasePrices);
                }
                //...
            }
        }
        scmApproveHisService.updateById(approveHisDO);
        scmUserApproveRefService.updateById(scmUserApproveRef);
        scmUserApproveRefService.updateBatchById(scmRefList);
        return Response.succeed();
    }

    @Override
    public Response<?> rejection(Integer id) {
        // 反写源单状态、修改审批历史记录
        return null;
    }

    @Override
    public Response<?> transfer(Integer id, Integer transferee) {
        // 修改审批历史记录
        return null;
    }

    @Override
    public Response<?> del(List<Long> ids) {
        List<ScmPurchasePlan> purchasePlansOfStaging = this.list(new LambdaQueryWrapper<ScmPurchasePlan>()
                .in(ScmPurchasePlan::getId, ids).eq(ScmPurchasePlan::getApproveStatus,Const.ApproveStatus.STAGING));
        if (ids.size() != purchasePlansOfStaging.size()){
            return Response.fail("不能删除非暂存状态单据，操作失败！");
        }
        this.removeByIds(ids);
        return Response.succeed();
    }

    @Override
    public Response<?> findPageListByParam(ScmPurchasePlanPageParam scmPurchasePlanPageParam) {
        //分页
        Page<ScmPurchasePlanPageVo> page = new Page<>(scmPurchasePlanPageParam.getCurrentPage(), scmPurchasePlanPageParam.getPageSize());
        //查询分页
        IPage<ScmPurchasePlanPageVo> pageList = this.baseMapper.findListByParam(page, scmPurchasePlanPageParam);
        if (ObjectUtil.isNotEmpty(pageList.getRecords())){
            pageList.getRecords().forEach(item ->{
                item.setViceNum((ObjectUtil.isEmpty(item.getNeedNum()) || item.getNeedNum().equals(BigDecimal.ZERO) || ObjectUtil.isEmpty(item.getMaterialConvCoefficient())) ?
                        BigDecimal.ZERO : item.getNeedNum().multiply(item.getMaterialConvCoefficient()));
            });
        }

        return Response.succeed(pageList);
    }

    @Override
    public List<ScmPurchasePlanPageVo> findListByParam(ScmPurchasePlanPageParam scmPurchasePageParam) {
        //分页
        //查询分页
        List<ScmPurchasePlanPageVo> list = this.baseMapper.findListByParam(scmPurchasePageParam);
        list.forEach(item ->{
                item.setViceNum((ObjectUtil.isEmpty(item.getNeedNum()) || item.getNeedNum().equals(BigDecimal.ZERO) || ObjectUtil.isEmpty(item.getMaterialConvCoefficient())) ?
                        BigDecimal.ZERO : item.getNeedNum().multiply(item.getMaterialConvCoefficient()));
            });

        return list;
    }

    @Override
    public ScmPurchasePlanVo  getScmPurchase(Integer id) {
        ScmPurchasePlanVo  purchasePlanVo = this.baseMapper.getScmPurchasePlan(id);
        ScmPurchasePlanItemParam planItemParam = new ScmPurchasePlanItemParam();
        planItemParam.setPurchasePlanId(id);
        List<ScmPurchasePlanItemVo>  purchasePlanItemList = scmPurchasePlanItemService.listPurchaseItem(planItemParam);
        purchasePlanItemList.forEach(item ->{
            item.setViceNum((ObjectUtil.isEmpty(item.getNeedNum()) || item.getNeedNum().equals(BigDecimal.ZERO) || ObjectUtil.isEmpty(item.getConvCoefficient())) ?
                    BigDecimal.ZERO : item.getNeedNum().multiply(item.getConvCoefficient()));
        });
        purchasePlanVo.setItemList(purchasePlanItemList);
        return purchasePlanVo;
    }




    /**
     * 新增节点
     * @param sourceCode 源单编码
     * @param sourceId 源单id
     * @param tabName 表单名称
     * @param num 新增节点顺序
     */
    public void approveNodeAdd(String sourceCode, Integer sourceId,Integer sourceType, Integer num, String tabName){
        LambdaQueryWrapper<SysApproveFlow> flowWrapper = new LambdaQueryWrapper<>();
        flowWrapper.eq(SysApproveFlow::getTabName,tabName);
        flowWrapper.eq(SysApproveFlow::getFlowStatus,Const.USER_STATUS_NORMAL);
        List<SysApproveFlow> flowList = sysApproveFlowService.list(flowWrapper);
        if (ObjectUtil.isEmpty(flowList) || flowList.size() != 1){
            throw new BDException("采购审批流程设置异常，请联系管理员！");
        }
        SysApproveFlow flowDO = flowList.get(0);
        LambdaQueryWrapper<SysApproveFlowNode> nodeWrapper = new LambdaQueryWrapper<>();
        nodeWrapper.eq(SysApproveFlowNode::getFlowId,flowDO.getId());
        List<SysApproveFlowNode> nodeList = sysApproveFlowNodeService.list(nodeWrapper);
        nodeWrapper.eq(SysApproveFlowNode::getNum, num);
        SysApproveFlowNode flowNodeDO = sysApproveFlowNodeService.getOne(nodeWrapper);
        ScmApproveHis scmApproveHis = new ScmApproveHis();
        scmApproveHis.setSourceType(sourceType);
        scmApproveHis.setSourceCode(sourceCode);
        scmApproveHis.setSourceId(sourceId);
        scmApproveHis.setFlowId(flowDO.getId());
        scmApproveHis.setFlowName(flowDO.getFlowName());
        scmApproveHis.setFlowNodeId(flowNodeDO.getId());
        scmApproveHis.setNodeName(flowNodeDO.getNodeName());
        scmApproveHis.setNum(flowNodeDO.getNum());
        scmApproveHis.setExecutionTimeLimit(flowNodeDO.getExecutionTimeLimit());
        scmApproveHis.setIsCountersign(flowNodeDO.getIsCountersign());
        scmApproveHis.setDoNextNode((nodeList.size() > flowNodeDO.getNum()) ? 1 : 0);
        scmApproveHis.setDoComplete(0);
        scmApproveHisService.save(scmApproveHis);
        LambdaQueryWrapper<SysApproveNodeRel> nodeRelWrapper = new LambdaQueryWrapper<>();
        nodeRelWrapper.eq(SysApproveNodeRel::getNodeId,flowNodeDO.getId());
        List<SysApproveNodeRel> nodeRelDOS = sysApproveNodeRelService.list(nodeRelWrapper);
        List<Integer> resourceIds = nodeRelDOS.stream().map(SysApproveNodeRel::getResourceId).collect(Collectors.toList());
        Integer flowType = flowNodeDO.getFlowType();
        List<ScmUserApproveRef> refDOS = new ArrayList<>();
        if (flowType.equals(1)){
            LambdaQueryWrapper<SysUser> userWrapper = new LambdaQueryWrapper<>();
            userWrapper.in(SysUser::getId,resourceIds);
            List<SysUser> sysUserDOS = userService.list(userWrapper);
            refDOS = sysUserDOS.stream().map(item -> {
                ScmUserApproveRef refDO = new ScmUserApproveRef();
                refDO.setApproveId(scmApproveHis.getId());
                refDO.setApproveResult(Const.ApproveResult.weichuli);
                refDO.setApprovePersonId(item.getId());
                refDO.setDoComplete(0);
                refDO.setApprovePersonName(item.getRealName());
                return refDO;
            }).collect(Collectors.toList());
        }
        if (flowType.equals(2)){
            LambdaQueryWrapper<SysUserRole> userRoleWrapper = new LambdaQueryWrapper<>();
            userRoleWrapper.in(SysUserRole::getRoleId,resourceIds);
            List<SysUserRole> userRoleList = sysUserRoleService.list(userRoleWrapper);
            List<Integer> userIds = userRoleList.stream().map(SysUserRole::getUserId).collect(Collectors.toList());
            LambdaQueryWrapper<SysUser> userWrapper = new LambdaQueryWrapper<>();
            userWrapper.in(SysUser::getId,userWrapper);
            List<SysUser> userDOS = userService.list(userWrapper);
            Map<Integer, SysUser> userDOSMapId = userDOS.stream().collect(Collectors.toMap(item -> item.getId(), item -> item, (v1, v2) -> v1));
            refDOS = userRoleList.stream().map(item -> {
                ScmUserApproveRef refDO = new ScmUserApproveRef();
                refDO.setApproveId(scmApproveHis.getId());
                refDO.setApproveResult(Const.ApproveResult.weichuli);
                refDO.setApprovePersonId(item.getUserId());
                refDO.setDoComplete(0);
                refDO.setApprovePersonName(userDOSMapId.containsKey(item.getUserId()) ? userDOSMapId.get(item.getUserId()).getRealName() : "");
                return refDO;
            }).collect(Collectors.toList());
        }
        if (flowType.equals(3)){
            LambdaQueryWrapper<SysUser> userWrapper = new LambdaQueryWrapper<>();
            userWrapper.in(SysUser::getDeptId,resourceIds);
            List<SysUser> userDOS = userService.list(userWrapper);
            refDOS = userDOS.stream().map(item -> {
                ScmUserApproveRef refDO = new ScmUserApproveRef();
                refDO.setApproveId(scmApproveHis.getId());
                refDO.setApproveResult(Const.ApproveResult.weichuli);
                refDO.setApprovePersonId(item.getId());
                refDO.setDoComplete(0);
                refDO.setApprovePersonName(item.getRealName());
                return refDO;
            }).collect(Collectors.toList());
        }
        scmUserApproveRefService.saveBatch(refDOS);
    }


    @Override
    public SysCountDTO inPurchase(){
        SysCountDTO result = new SysCountDTO();
        result.setName1("采购在途订单");
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("do_close",0);
        queryWrapper.eq("approve_status",3);
        result.setValue1(String.valueOf(this.count(queryWrapper)));

        result.setName2("月度采购次数");
        QueryWrapper queryWrapper2 = new QueryWrapper();
        queryWrapper2.eq("do_close",0);
        queryWrapper2.eq("approve_status",3);
        SimpleDateFormat simpleDateFormat  = new SimpleDateFormat("yyyy-MM");
        String d = simpleDateFormat.format(new Date());
        queryWrapper2.eq("DATE_FORMAT(apply_time, '%Y-%m')",d);
        result.setValue2(String.valueOf(this.count()));
        return result;
    }



}




